#include "sgu.h"

SGU_NS_BEGIN

//**** BIStorage

BIStorage::BIStorage(const ConstSegment & data) : _data(data)
{
	_data.addUser(this);
	_ptr = 0;
}

BIStorage::~BIStorage()
{
	ASSERT(_blocks.empty());
	//if(_ptr != _data.size()) logmsg();
	_data.delUser(this);
}

const char * BIStorage::queryPtr() const
{
	return _data.cptr() + _ptr;
}

BIStorage & BIStorage::operator >> (Cmd cmd)
{
	switch(cmd)
	{
		case BEGIN:
		{
			size_t base = _ptr;
			size_t z;
			(*this) >> z;
			_blocks.push(base+z);
		}; break;
			
		case END:
		{
			ASSERT(!_blocks.empty());
			size_t shld = _blocks.top();
			if(_ptr != shld) THROWSGUFUNCEXCEPTION("/bad");
			_blocks.pop();
		}; break;

		case ABORT:
		{
			ASSERT(!_blocks.empty());
			size_t shld = _blocks.top();
			_ptr = shld;
			_blocks.pop();
		}; break;

		default: ASSERT(false);
	}
	return *this;
}


void BIStorage::read(void * p, size_t n)
{
	if(_ptr + n > _data.size()) THROWSGUFUNCEXCEPTION("/eof");
	memcpy(p,_data.cptr()+_ptr,n);
	_ptr += n;
}

void BIStorage::skip(size_t n)
{
	if(_ptr + n > _data.size()) THROWSGUFUNCEXCEPTION("/eof");
	_ptr += n;
}
	


BIStorage & BIStorage::operator >> (Serializable & o)
{
	o.serialize(*this);
	return *this;
}

BIStorage & BIStorage::operator >> (unsigned int & n)
{
	read(&n,sizeof(n));
	return *this;
}

BIStorage & BIStorage::operator >> (int & n)
{
	read(&n,sizeof(n));
	return *this;
}

BIStorage & BIStorage::operator >> (bool & n)
{
	read(&n,sizeof(n));
	return *this;
}

BIStorage & BIStorage::operator >> (double & n)
{
	read(&n,sizeof(n));
	return *this;
}


BIStorage & BIStorage::operator >> (std::string & a)
{
	size_t sz;
	(*this) >> sz;
	a = std::string(queryPtr(),sz);
	skip(sz);
	return *this;
}

BIStorage & BIStorage::operator >> (std::wstring & a)
{
	size_t sz;
	(*this) >> sz;
	sz *= sizeof(wchar_t);
	a = std::wstring((const wchar_t *)queryPtr(),sz);
	skip(sz);
	return *this;
}


//**** BOStorage

BOStorage::BOStorage(DynamicSegment & data) : _data(data)
{
	_data.addUser(this);
	_ptr = 0;
}

BOStorage::~BOStorage()
{
	ASSERT(_blocks.empty());
	_data.delUser(this);
}

void BOStorage::write(const void * p, size_t n)
{
	_data.resize(_ptr+n);
	memcpy(_data.ptr()+_ptr,p,n);
	_ptr += n;
}


BOStorage & BOStorage::operator << (const Serializable & o)
{
	o.serialize(*this);
	return *this;
}

BOStorage & BOStorage::operator << (Cmd cmd)
{
	switch(cmd)
	{
		case BEGIN:
		{
			_blocks.push(_ptr);
			_ptr += sizeof(size_t);
		}; break;
			
		case END:
		{
			ASSERT(!_blocks.empty());
			size_t prev = _blocks.top();
			_blocks.pop();
			size_t dist = _ptr - prev;
			memcpy(_data.ptr()+prev,&dist,sizeof(size_t));
		}; break;

		default: ASSERT(false);
	}
	return *this;
}

BOStorage & BOStorage::operator << (unsigned int n)
{
	write(&n,sizeof(n));
	return *this;
}

BOStorage & BOStorage::operator << (int n)
{
	write(&n,sizeof(n));
	return *this;
}

BOStorage & BOStorage::operator << (bool n)
{
	write(&n,sizeof(n));
	return *this;
}

BOStorage & BOStorage::operator << (double n)
{
	write(&n,sizeof(n));
	return *this;
}


BOStorage & BOStorage::operator << (const std::string & a)
{
	size_t sz = a.size();
	(*this) << sz;
	write(a.data(),sz);
	return *this;
}

BOStorage & BOStorage::operator << (const std::wstring & a)
{
	size_t sz = a.size();
	(*this) << sz;
	write(a.data(),sz*sizeof(wchar_t));
	return *this;
}

SGU_NS_END
